﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;

namespace AppConfig
{
    public class AppBase
    {
        public string Name { get; set; }

        public Func<string, string> Location { get; set; }

    }

    public class CSharpApp:AppBase
    {
        public string Location { get; set; }

        public string[] Assemblies { get; set; }

        public string EntryPoint { get; set; }

        public string Hash { get; set; }

        public string CachePath
        {
            get
            {
                return GetCachePath(Name);
            }
        }

        private string GetCachePath(string Name)
        {
            throw new NotImplementedException();
        }

        #region Read from xml

        static Dictionary<string, string> BasePaths;

        static string AppConfigPath
        {
            get { return System.Configuration.ConfigurationManager.AppSettings["appStorePath"]; }
        }


        public static IEnumerable<CSharpApp> AppList { get; private set; }

        static CSharpApp()
        {
            var path = AppConfigPath;
            if (!File.Exists(path))
                path = Path.Combine(Environment.CurrentDirectory, "..\\..\\", Path.GetFileName(path));

            var xd = XDocument.Load(path);

            AppList = xd.Document.Descendants("app").Select(n => new CSharpApp
            {
                Name = n.Element("Name").Value,
                Location = n.Element("Location").Value,
                EntryPoint = n.Element("EntryPoint").Value,
                Assemblies = n.Element("Assemblies").Value.Split(','),              
            });

            BasePaths = xd.Document.Descendants("paths").Single().Descendants("add")
                .ToDictionary(e => e.Attribute("key").Value, e => e.Attribute("value").Value);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="path">Relative path</param>
        /// <returns></returns>
        public static string GetContent(string path)
        {
            if (BasePaths.Count == 0)
                return File.ReadAllText(path);

            foreach (var item in BasePaths.Values)
            {
                var fullPath = System.IO.Path.Combine(item, path);

                if (File.Exists(fullPath))
                    return File.ReadAllText(fullPath);
            }

            throw new FileNotFoundException(String.Format("File [{0}] Not Found.", path));
        }

        public static string CreateMd5ForFolder(string path)
        {
            // assuming you want to include nested folders
            var files = Directory.GetFiles(path, "*.*", SearchOption.AllDirectories)
                                 .OrderBy(p => p).ToList();

            MD5 md5 = MD5.Create();
            
            for (int i = 0; i < files.Count; i++)
            {
                string file = files[i];

                // hash path
                string relativePath = file.Substring(path.Length + 1);
                byte[] pathBytes = Encoding.UTF8.GetBytes(relativePath.ToLower());
                md5.TransformBlock(pathBytes, 0, pathBytes.Length, pathBytes, 0);

                // hash contents
                byte[] contentBytes = File.ReadAllBytes(file);
                if (i == files.Count - 1)
                    md5.TransformFinalBlock(contentBytes, 0, contentBytes.Length);
                else
                    md5.TransformBlock(contentBytes, 0, contentBytes.Length, contentBytes, 0);
            }

            return BitConverter.ToString(md5.Hash).Replace("-", "").ToLower();
        }
        #endregion
    }

}
